`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
*****************************************************************************/

/**
	@file cache.v
	@author griffin.milsap@gmail.com
	@brief A single 4k Direct Mapped Cache block
		Largely adapted from Andrew's dummy L1 direct mapped cache
**/

module cache(
	clk, noncache, query_done,
	up_rd, up_wr, up_mask, up_addr, up_din, up_dout, up_doutok, // Upstream (toward CPU) bus
	dn_rd, dn_wr, dn_mask, dn_addr, dn_din, dn_dout, dn_dinok   // Downstream (away from CPU) bus
	);

	// IO Definitions
	input wire clk;
	input wire noncache;
	output reg query_done;
	
	// Upstream bus
	input wire up_rd;
	input wire up_wr;
	input wire[3:0] up_mask;
	input wire[31:0] up_addr;
	input wire[31:0] up_din;
	output reg[31:0] up_dout = 0;
	output reg up_doutok = 0;

	// Downstream bus
	output reg dn_rd = 0;
	output reg dn_wr = 0;
	output reg[3:0] dn_mask = 0;
	output reg[31:0] dn_addr = 0;
	input wire[31:0] dn_din;
	output reg[31:0] dn_dout = 0;
	input wire dn_dinok;
	
	// Buffer the downstream address
	reg[31:0] dn_addr_buf = 0;
	always @(posedge clk) begin
		dn_addr_buf <= dn_addr;
	end
	
	// Forwarding
	wire uncacheable; // If set, don't cache this
	assign uncacheable = (up_addr[31:29] == 3'b101);
	
	wire cache_hit;
	
	reg[31:0] up_addr_buf = 0;
	reg uncacheable_buf = 0;
	always @(posedge clk) begin
		up_addr_buf <= up_addr;
		uncacheable_buf = uncacheable;
	end
	
	reg[31:0] saved_read_addr = 0;
	reg pending_read = 0;
	reg pending_read_enabled = 0;
	
	// Decide whether or not to read out data bus this cycle
	wire read_from_dn;
	reg read_from_dn_buf = 0;
	
	reg saved_read_addr_valid = 0;
	
	// If this is a cacheable read, store the address and spam until hit
	always @(posedge clk) begin
		read_from_dn_buf <= read_from_dn;
		
		// New cached read, save it; pending read, stall.
		if(up_rd && !uncacheable && !pending_read && !noncache) begin
			pending_read <= 1;
			pending_read_enabled <= 0;
			saved_read_addr <= up_addr;
			saved_read_addr_valid <= 1;
		end
		
		// If a read has finished, determine if it was a hit
		if(up_addr_buf == saved_read_addr && saved_read_addr_valid) begin
			
			// If it is a hit, we don't have to go downstream
			if(cache_hit) begin
				pending_read <= 0;
				saved_read_addr <= 0;
				saved_read_addr_valid <= 0;
				pending_read_enabled <= 0;
			end
			
			// If its a miss, we need to fetch it
			else begin
				pending_read_enabled <= 1;
			end
			
		end
		
		// Once a pending read has been dispatched, disable pending read
		if(read_from_dn) begin
			pending_read_enabled <= 0;
		end
		
		// If we got a downstream hit on this address, mark it as not fetched
		if(read_from_dn_buf && dn_dinok) begin
			pending_read <= 0;
			pending_read_enabled <= 0;
		end
		
		if(up_doutok) begin
			pending_read <= 0;
			pending_read_enabled <= 0;
		end
	end
	
	// Downstream bus control
	wire forward;
	assign forward = uncacheable | up_wr;
	assign read_from_dn = !forward && pending_read_enabled;
	
	// Cache is write through, so we always write downward
	// asynchronously
	always @(forward, up_addr, up_rd, up_wr, up_din, up_mask,
		read_from_dn, saved_read_addr) begin
		
		dn_addr <= 32'h0;
		dn_rd <= 1'b0;
		dn_wr <= 1'b0;
		dn_dout <= 32'b0;
		dn_mask <= 32'b0;
		
		// Cache forwarding
		if(forward) begin
			dn_addr <= up_addr;
			dn_rd <= up_rd;
			dn_wr <= up_wr;
			dn_dout <= up_din;
			dn_mask <= up_mask;
		end
		
		// Reading downstream if there is a cache miss
		else if(read_from_dn) begin
			dn_addr <= saved_read_addr;
			dn_rd <= 1;
		end
		
	end
	
	// Synchronous buffer forward flag
	reg forward_buf = 0;
	always @(posedge clk) begin
		forward_buf <= forward;
	end
	
	wire[31:0] cache_dout;
	
	// Forwarding of responses to results
	always @(forward_buf, dn_din, cache_dout, dn_dinok, cache_hit, up_rd_buf) begin
		up_dout <= 32'h0;
		up_doutok <= 0;
		query_done <= 0;
		
		//if(forward_buf) begin
		if(dn_dinok) begin
			up_dout <= dn_din;
			up_doutok <= dn_dinok;
		end
		
		else if(up_rd_buf) begin
			up_dout <= cache_dout;
			up_doutok <= cache_hit;
			query_done <= 1;
		end
		
	end
	
	// Remember if we were reading
	reg up_rd_buf = 0;
	always @(posedge clk) begin
		up_rd_buf <= up_rd;
	end
	
	// Handle Cache Miss
	
	// TODO: Write logic here
	always @(posedge clk) begin
	
		// Write miss
		if(up_wr) begin
		
			// Uncached Write
			if(uncacheable) begin
				
			end
			
			// Cached Write
			else begin
				if( up_mask == 4'b1111) begin
				
				end
				else begin
				
				end
			end
			
		end
		
		// Read Miss
		if(up_rd) begin
		
			// Uncached Read
			if(uncacheable) begin
			
			end
			
			// Cached Read
			else begin
			
			end
			
		end
		
		// Second clock of a cached read
		if(up_rd_buf && !uncacheable_buf) begin
			if(cache_hit) begin
			
			end
			else begin
			
			end
		end
	end
	
	// In bank addressing and hit processing
	
	// Data from up/downstream to cache
	wire[35:0] cache_in_up;
	assign cache_in_up = {up_addr[15:12], up_din};
	wire[35:0] cache_in_dn;
	assign cache_in_dn = {dn_addr_buf[15:12], dn_din};
	
	wire full_word_write;
	assign full_word_write = (up_mask == 4'b1111);
	
	// Tag data from up/downstream to cache
	// If the write is not a full word, just clear the valid bit
	wire[17:0] tag_in_up;
	assign tag_in_up = {1'b0, full_word_write, up_addr[31:16]};
	wire[17:0] tag_in_dn;
	assign tag_in_dn = {1'b0, 1'b1, dn_addr_buf[31:16]};
	
	// Possibility of adding a second bank for addressing purposes
	wire[35:0] cache_out_low;
	wire[35:0] cache_out_high;
	
	// Mux output of the cache banks
	wire[35:0] cache_out;
	assign cache_out = up_addr_buf[11] ? cache_out_high : cache_out_low;
	assign cache_dout = cache_out[31:0];
	
	// Read and Write enables
	wire up_en_low;
	wire dn_en_low;
	wire[3:0] up_we_low;
	wire[3:0] dn_we_low;
	wire up_en_high;
	wire dn_en_high;
	wire[3:0] up_we_high;
	wire[3:0] dn_we_high;
	
	// Check if we had any read-write collisions on the cache
	wire addr_collide;
	assign addr_collide = (up_addr[11:2] == dn_addr_buf[11:2]) && read_from_dn_buf;
	
	assign up_en_low = !up_addr[11] && !addr_collide;
	assign up_en_high = up_addr[11] && !addr_collide;
	assign dn_en_low = !dn_addr_buf[11] && read_from_dn_buf;
	assign dn_en_high = dn_addr_buf[11] && read_from_dn_buf;
	
	// Write enable (Consider masking!)
	wire up_we;
	wire[1:0] up_we_tag;
	wire[1:0] dn_we_tag;
	assign up_we = up_wr & !uncacheable;
	assign up_we_high = {up_we, up_we, up_we, up_we};
	assign up_we_low  = {up_we, up_we, up_we, up_we};
	assign up_we_tag  = {up_we, up_we};
	assign dn_we_low  = {dn_dinok, dn_dinok, dn_dinok, dn_dinok};
	assign dn_we_high = {dn_dinok, dn_dinok, dn_dinok, dn_dinok};
	assign dn_we_tag  = {dn_dinok, dn_dinok};
	
	wire[17:0] tag_out_high;
	
	// Reconstruct tag data
	wire tag_valid = tag_out_high[16];
	wire[19:0] tag_out;
	assign tag_out = {tag_out_high[15:0], cache_out[35:32]};
	
	// See if the read returned a cache hit
	assign cache_hit = !uncacheable_buf && (tag_out == up_addr_buf[31:12]) && !addr_collide && tag_valid;

	// Memory Definitions
	// Data Block
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(36'h00000000),
		.INIT_B(36'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (36),
		.READ_WIDTH_B (36),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(36),
		.WRITE_WIDTH_B(36),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) data_block_low (
		.DOA(cache_out_low),
		//.DOB(NOCONNECT),         //Downstream cannot read from us, only write
		.ADDRA(up_addr[10:2]),     //Pull appropriate bits of address out
		.ADDRB(dn_addr_buf[10:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(cache_in_up),
		.DIB(cache_in_dn),
		.ENA(up_en_low),
		.ENB(dn_en_low),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA(up_we_low),
		.WEB(dn_we_low)
		);
		
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(36'h0000000),
		.INIT_B(36'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (36),
		.READ_WIDTH_B (36),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(36),
		.WRITE_WIDTH_B(36),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) data_block_high (
		.DOA(cache_out_high),
		//.DOB(NOCONNECT),         // Downstream cannot read from us, only write
		.ADDRA(up_addr[10:2]),     // Pull appropriate bits of address out
		.ADDRB(dn_addr_buf[10:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(cache_in_up),
		.DIB(cache_in_dn),
		.ENA(up_en_high),
		.ENB(dn_en_high),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA(up_we_high),
		.WEB(dn_we_high)
		);
	
	// Tag Block
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(18'h00000000),
		.INIT_B(18'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (18),
		.READ_WIDTH_B (18),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(18),
		.WRITE_WIDTH_B(18),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) tag_block (
		.DOA(tag_out_high),
		//.DOB(NOCONNECT),         // Downstream cache/device cannot read from us, only write
		.ADDRA(up_addr[11:2]),     // Pull appropriate bits of address out
		.ADDRB(dn_addr_buf[11:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(tag_in_up),
		.DIB(tag_in_dn),
		.ENA(!addr_collide),
		.ENB(read_from_dn_buf),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA(up_we_tag),
		.WEB(dn_we_tag)
		);

endmodule
